#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <GL/glu.h>
#include <GL/gl.h>
#include <GL/glut.h>
#include "punto.h"

int i =0;

int numPuntos;
int maxX, maxY;
int minRX, maxRX;
int minRY, maxRY;

Punto puntoInicial;
ListaPunto puntosMoviles;
puntoDelEspacio** espacio;

bool dibuja_perimetro = false;
bool dibuja_perRestrincion = false;

void inicializaVariables(int numpts, int maxX, int maxY);
void liberaMemoria();

//MÉTODOS GRÁFICOS
	void dibujaPuntos();
	void mueve_puntos();
	void teclaPresionada(unsigned char tecla, int x, int y);
	void raton(int boton, int estado, int x, int y);
	void ventanaEscalada(int x, int y);

int main(int argcp, char** argv){
	glutInit(&argcp, argv);
	
	//INICIALIZACIÓN____________________________________________________________
		srand(time(NULL));	//Creamos la remilla para la funión rand() con la hora actual
		
		inicializaVariables(16,4,4);
		
		inicializaEspacio(espacio, maxX, maxY);
		inicializaPuntos(puntosMoviles, numPuntos, maxX, maxY);
		ponPuntoQuieto(puntoInicial, espacio, &minRX, &maxRX, &minRY, &maxRY, maxX, maxY);		
	
		glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
		glutInitWindowPosition(0, 0);
		glutInitWindowSize(maxX, maxY);
		glutCreateWindow("FRACTAL");

		gluOrtho2D(0.0, maxX, 0.0, maxY);
		
	//BUCLE GLUT________________________________________________________________		
		glutDisplayFunc(dibujaPuntos);
		glutKeyboardFunc(teclaPresionada);
		glutMouseFunc(raton);
		glutReshapeFunc(ventanaEscalada);
		glutIdleFunc(mueve_puntos);
	
		glutMainLoop();
}


void inicializaVariables(int numpts, int maxx, int maxy){
	if(numpts > maxx*maxy){
		printf("No caben tantos puntos");
		exit(1);
	}
	
	numPuntos = numpts;
	maxX = maxx;
	maxY = maxy;
	
	//Los máximos y mínimos relativos se inicializan con valores contrarios
	//para asegurarse que son modificados al comenzar el algoritmo
	minRX = maxX;
	minRY = maxY;
	maxRX = 0;
	maxRY = 0;
	
	puntoInicial.x = maxX/2;
	puntoInicial.y = maxY/2;

	puntosMoviles = ls_inicializa();
	espacio = (puntoDelEspacio**) malloc(sizeof(puntoDelEspacio*) * maxX);
	int i;
	for(i = 0 ; i < maxX ; i++){
		espacio[i] = (puntoDelEspacio*) malloc(sizeof(puntoDelEspacio) * maxY);
		if(!espacio[i]){
			printf("No se ha podido reservar la memória\n");
			exit(1);
		}	
	}

	if(!espacio){
		printf("No se ha podido reservar la memória\n");
		exit(1);
	}
}

void liberaMemoria(){
	ls_free(puntosMoviles);
	int i;
	for(i = 0 ; i < maxX ; i++){
		free(espacio[i]);
	}
	free(espacio);
	printf("¡MEMORIA LIBERADA!");
}

void dibujaPuntos(){
	
	int i,j;
	NodoPunto* nodo;
	
	//glPointSize(2);
	glColor3f(1.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    
	//PUNTOS MOVILES
		glColor3f(1.0, 1.0, 1.0);
		nodo = puntosMoviles->primero;
		glBegin(GL_POINTS);
		while(nodo){
			glVertex2f(nodo->punto.x, nodo->punto.y);
			
			nodo = nodo->siguiente;
		}
		glEnd();	
		
	//PUNTOS QUIETOS Y PERIMETRO
		glBegin(GL_POINTS);
		for(i = minRX; i < maxRX ; i++){
			for(j = minRY; j < maxRY ; j++){
				if(espacio[i][j] == PUNTO_QUIETO){
					glColor3f(0.0, 0.0, 1.0);
					glVertex2f(i,j);
				}
				else if(dibuja_perimetro && espacio[i][j] == PERIMETRO){
					glColor3f(0.0, 1.0, 0.0);
					glVertex2f(i,j);
				}
			}
		}
		glEnd();
		
	//PERIMETRO DE RESTRINCIÓN DE DIBUJADO
		if(dibuja_perRestrincion){
			glColor3f(1.0, 1.0, 0.0);
			glBegin(GL_LINE_LOOP);
				glVertex2f(minRX,maxRY);
				glVertex2f(maxRX,maxRY);
				glVertex2f(maxRX,minRY);
				glVertex2f(minRX,minRY);
			glEnd();
		}
	
	glutSwapBuffers();
}

void mueve_puntos(){
	if(puntosMoviles->tamanyo){
		printf("- %i - PUNTOS\n",i);
		imprimePuntos(puntosMoviles);
		muevePuntos(puntosMoviles, espacio, &minRX, &maxRX, &minRY, &maxRY, maxX, maxY);
		i++;
		glutPostRedisplay();
	}
}

void teclaPresionada(unsigned char tecla, int x, int y) {
	
	switch (tecla) {
		case 27:	//Escape key
			liberaMemoria();
			exit(0); //Exit the program
		break;
		
		case 112:	//p key
			dibuja_perimetro = !dibuja_perimetro;
		break;
		
		case 114:	//r key
			dibuja_perRestrincion = !dibuja_perRestrincion;
		break;
	}
}

void raton (int boton, int estado, int x, int y){
	if(boton == GLUT_LEFT_BUTTON && estado == GLUT_DOWN){
		Punto p = {x,maxY-y};
		ponPuntoQuieto(p, espacio, &minRX, &maxRX, &minRY, &maxRY, maxX, maxY);
	}
}

void ventanaEscalada(int x, int y){
	glutReshapeWindow(maxX,maxY);
}
